# -*- coding: utf-8 -*-
# Author   : ZhangQing
# Time     : 2025-07-08 6:44
# File     : visualization.py
# Project  : risk-contagion-analysis
# Desc     :

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import networkx as nx
import numpy as np
import logging
import io
import base64
from matplotlib.colors import LinearSegmentedColormap
from matplotlib.figure import Figure


class ResultVisualizer:
    def __init__(self):
        """初始化结果可视化器"""
        self.logger = self._setup_logger()

        # 设置绘图风格
        plt.style.use('seaborn-whitegrid')
        sns.set(style="whitegrid", palette="muted", font_scale=1.2)

        # 自定义配色方案
        self.colors = {
            'risk': '#FF5252',  # 红色
            'protection': '#4CAF50',  # 绿色
            'network': '#2196F3',  # 蓝色
            'reputation': '#FFC107',  # 黄色
            'background': '#FAFAFA',  # 浅灰色
            'text': '#212121'  # 深灰色
        }

    def _setup_logger(self):
        """设置日志记录器"""
        logger = logging.getLogger("ResultVisualizer")
        logger.setLevel(logging.INFO)
        handler = logging.StreamHandler()
        formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        handler.setFormatter(formatter)
        logger.addHandler(handler)
        return logger

    def _setup_custom_colors(self):
        """设置自定义颜色映射"""
        # 风险热图颜色映射
        self.risk_cmap = LinearSegmentedColormap.from_list(
            "risk_gradient",
            [(0.0, "#4CAF50"), (0.5, "#FFEB3B"), (1.0, "#FF5252")]
        )

        # 网络关系颜色映射
        self.network_cmap = LinearSegmentedColormap.from_list(
            "network_gradient",
            [(0.0, "#E3F2FD"), (1.0, "#1565C0")]
        )

    def plot_risk_distribution(self, risk_df):
        """绘制风险暴露分布图

        Args:
            risk_df: 包含风险评分的数据框

        Returns:
            str: 图像的base64编码
        """
        self.logger.info("绘制风险暴露分布图...")

        # 创建图表
        fig, ax = plt.subplots(figsize=(10, 6))

        # 绘制风险得分分布
        sns.histplot(
            data=risk_df,
            x="risk_score",
            color=self.colors['risk'],
            kde=True,
            alpha=0.6,
            ax=ax
        )

        # 绘制防护得分分布
        sns.histplot(
            data=risk_df,
            x="protection_score",
            color=self.colors['protection'],
            kde=True,
            alpha=0.6,
            ax=ax
        )

        # 设置图表样式
        ax.set_facecolor(self.colors['background'])
        ax.set_title("风险暴露与防护能力分布", fontsize=16, color=self.colors['text'])
        ax.set_xlabel("得分", fontsize=12, color=self.colors['text'])
        ax.set_ylabel("频率", fontsize=12, color=self.colors['text'])

        # 添加图例
        ax.legend(["风险得分", "防护得分"], fontsize=10)

        # 添加网格线
        ax.grid(True, linestyle='--', alpha=0.7)

        # 调整布局
        fig.tight_layout()

        # 转换为base64编码
        buffer = io.BytesIO()
        fig.savefig(buffer, format='png', dpi=300, bbox_inches='tight')
        buffer.seek(0)
        img_str = base64.b64encode(buffer.read()).decode('utf-8')
        plt.close(fig)

        return img_str

    def plot_net_risk_exposure_by_year(self, risk_df):
        """绘制年度净风险暴露趋势图

        Args:
            risk_df: 包含风险评分的数据框

        Returns:
            str: 图像的base64编码
        """
        self.logger.info("绘制年度净风险暴露趋势图...")

        # 计算每年的平均净风险暴露
        yearly_risk = risk_df.groupby('year').agg({
            'risk_score': 'mean',
            'protection_score': 'mean',
            'net_risk_exposure': 'mean'
        }).reset_index()

        # 创建图表
        fig = make_subplots(specs=[[{"secondary_y": True}]])

        # 添加风险得分和防护得分线
        fig.add_trace(
            go.Scatter(
                x=yearly_risk['year'],
                y=yearly_risk['risk_score'],
                mode='lines+markers',
                name='风险得分',
                line=dict(color=self.colors['risk'], width=3),
                marker=dict(size=8)
            )
        )

        fig.add_trace(
            go.Scatter(
                x=yearly_risk['year'],
                y=yearly_risk['protection_score'],
                mode='lines+markers',
                name='防护得分',
                line=dict(color=self.colors['protection'], width=3),
                marker=dict(size=8)
            )
        )

        # 添加净风险暴露柱状图
        fig.add_trace(
            go.Bar(
                x=yearly_risk['year'],
                y=yearly_risk['net_risk_exposure'],
                name='净风险暴露',
                marker_color=self.colors['network'],
                opacity=0.7
            ),
            secondary_y=True
        )

        # 更新布局
        fig.update_layout(
            title='年度风险暴露与防护能力趋势',
            xaxis=dict(
                title='年份',
                tickmode='linear',
                dtick=1
            ),
            yaxis=dict(
                title='得分',
                gridcolor='lightgray'
            ),
            yaxis2=dict(
                title='净风险暴露',
                gridcolor='lightgray',
                overlaying='y',
                side='right'
            ),
            legend=dict(
                x=0.01,
                y=0.99,
                bgcolor='rgba(255, 255, 255, 0.8)',
                bordercolor='rgba(0, 0, 0, 0.1)',
                borderwidth=1
            ),
            plot_bgcolor=self.colors['background'],
            margin=dict(l=20, r=20, t=60, b=20),
            height=600
        )

        # 转换为HTML
        plot_html = fig.to_html(full_html=False, include_plotlyjs='cdn')

        return plot_html

    def plot_risk_heatmap_by_industry(self, risk_df, industry_column='industry'):
        """绘制行业风险热图

        Args:
            risk_df: 包含风险评分和行业的数据框
            industry_column: 行业列名

        Returns:
            str: 图像的base64编码
        """
        self.logger.info("绘制行业风险热图...")

        # 确保存在行业列
        if industry_column not in risk_df.columns:
            self.logger.error(f"数据框中不存在列 '{industry_column}'")
            return None

        # 计算各行业的平均风险指标
        industry_risk = risk_df.groupby(industry_column).agg({
            'risk_score': 'mean',
            'protection_score': 'mean',
            'net_risk_exposure': 'mean'
        }).reset_index()

        # 按净风险暴露降序排序
        industry_risk = industry_risk.sort_values('net_risk_exposure', ascending=False)

        # 创建热图数据
        heatmap_data = []
        for _, row in industry_risk.iterrows():
            heatmap_data.append([row[industry_column], '风险得分', row['risk_score']])
            heatmap_data.append([row[industry_column], '防护得分', row['protection_score']])
            heatmap_data.append([row[industry_column], '净风险暴露', row['net_risk_exposure']])

        heatmap_df = pd.DataFrame(heatmap_data, columns=['行业', '指标', '得分'])

        # 透视表转换
        heatmap_pivot = heatmap_df.pivot(index='行业', columns='指标', values='得分')

        # 创建热图
        plt.figure(figsize=(12, len(industry_risk) * 0.6 + 2))
        ax = sns.heatmap(
            heatmap_pivot,
            annot=True,
            cmap=self.risk_cmap,
            fmt='.2f',
            linewidths=.5,
            cbar_kws={'label': '得分'}
        )

        plt.title('行业数字技术风险热图', fontsize=16)
        plt.tight_layout()

        # 转换为base64编码
        buffer = io.BytesIO()
        plt.savefig(buffer, format='png', dpi=300, bbox_inches='tight')
        buffer.seek(0)
        img_str = base64.b64encode(buffer.read()).decode('utf-8')
        plt.close()

        return img_str

    def plot_supply_chain_network(self, G, risk_df, top_n=30):
        """绘制供应链网络图

        Args:
            G: 供应链网络图
            risk_df: 包含风险评分的数据框
            top_n: 要显示的节点数量

        Returns:
            str: 图像的HTML代码
        """
        self.logger.info(f"绘制供应链网络图 (top {top_n} 节点)...")

        # 创建风险得分字典
        risk_dict = dict(zip(risk_df['stock_code'], risk_df['net_risk_exposure']))

        # 为网络中的节点添加风险属性
        for node in G.nodes():
            G.nodes[node]['risk'] = risk_dict.get(node, 0)

        # 获取连接度最高的前N个节点
        degree_dict = dict(G.degree(weight='weight'))
        top_nodes = sorted(degree_dict.items(), key=lambda x: x[1], reverse=True)[:top_n]
        top_nodes_ids = [node[0] for node in top_nodes]

        # 提取子图
        subgraph = G.subgraph(top_nodes_ids)

        # 计算布局
        pos = nx.spring_layout(subgraph, k=0.3, iterations=50, seed=42)

        # 获取节点大小 (基于度)
        node_size = [degree_dict[node] * 10 for node in subgraph.nodes()]

        # 获取节点颜色 (基于风险)
        node_risks = [subgraph.nodes[node].get('risk', 0) for node in subgraph.nodes()]

        # 规范化风险值
        max_risk = max(node_risks) if node_risks else 1
        node_colors = [n / max_risk for n in node_risks]

        # 获取边的权重
        edge_weights = [subgraph[u][v].get('weight', 1) for u, v in subgraph.edges()]
        max_weight = max(edge_weights) if edge_weights else 1
        edge_widths = [w / max_weight * 5 for w in edge_weights]

        # 创建网络图
        plt.figure(figsize=(12, 10))

        # 绘制边
        nx.draw_networkx_edges(
            subgraph,
            pos,
            alpha=0.3,
            width=edge_widths,
            edge_color='gray'
        )

        # 绘制节点
        nodes = nx.draw_networkx_nodes(
            subgraph,
            pos,
            node_size=node_size,
            node_color=node_colors,
            cmap=self.risk_cmap,
            alpha=0.8
        )

        # 添加颜色条
        plt.colorbar(nodes, label='风险暴露指数')

        # 添加标签 (仅对度最高的节点)
        top_5_nodes = sorted(degree_dict.items(), key=lambda x: x[1], reverse=True)[:5]
        top_5_ids = [node[0] for node in top_5_nodes]
        labels = {node: node for node in subgraph.nodes() if node in top_5_ids}
        nx.draw_networkx_labels(subgraph, pos, labels, font_size=10, font_weight='bold')

        # 设置图表样式
        plt.title("供应链网络与风险传导", fontsize=16)
        plt.axis('off')
        plt.tight_layout()

        # 转换为base64编码
        buffer = io.BytesIO()
        plt.savefig(buffer, format='png', dpi=300, bbox_inches='tight')
        buffer.seek(0)
        img_str = base64.b64encode(buffer.read()).decode('utf-8')
        plt.close()

        return img_str

    def plot_mediation_analysis(self, mediation_results):
        """绘制中介效应分析图

        Args:
            mediation_results: 中介效应分析结果

        Returns:
            str: 图像的base64编码
        """
        self.logger.info("绘制中介效应分析图...")

        # 提取关键发现
        key_findings = mediation_results['key_findings']

        # 创建图表
        fig, ax = plt.subplots(figsize=(10, 6))

        # 绘制路径
        paths = [
            ('直接效应', key_findings['direct_effect']),
            ('通过债务成本', key_findings['indirect_effect_debt']),
            ('通过利润波动性', key_findings['indirect_effect_vol'])
        ]

        paths_sorted = sorted(paths, key=lambda x: abs(x[1]), reverse=True)

        # 绘制效应大小
        bars = ax.barh(
            [p[0] for p in paths_sorted],
            [p[1] for p in paths_sorted],
            color=[self.colors['network'] if p[1] >= 0 else self.colors['risk'] for p in paths_sorted],
            alpha=0.7
        )

        # 添加数值标签
        for bar in bars:
            width = bar.get_width()
            label_x_pos = width + 0.01 if width >= 0 else width - 0.01
            ax.text(
                label_x_pos,
                bar.get_y() + bar.get_height() / 2,
                f'{width:.3f}',
                va='center',
                ha='left' if width >= 0 else 'right',
                fontweight='bold'
            )

        # 添加总效应
        ax.axvline(
            x=key_findings['total_effect'],
            color=self.colors['reputation'],
            linestyle='--',
            linewidth=2,
            label=f"总效应: {key_findings['total_effect']:.3f}"
        )

        # 设置图表样式
        ax.set_facecolor(self.colors['background'])
        ax.set_title("风险暴露影响企业价值的中介效应分解", fontsize=16, color=self.colors['text'])
        ax.set_xlabel("效应大小", fontsize=12, color=self.colors['text'])
        ax.set_ylabel("中介路径", fontsize=12, color=self.colors['text'])

        # 添加注释
        mediation_percentage = key_findings['mediation_proportion'] * 100
        ax.text(
            0.05, 0.05,
            f"中介效应比例: {mediation_percentage:.1f}%",
            transform=ax.transAxes,
            fontsize=12,
            bbox=dict(facecolor='white', alpha=0.8, boxstyle='round,pad=0.5')
        )

        # 添加图例
        ax.legend(loc='upper right')

        # 调整布局
        fig.tight_layout()

        # 转换为base64编码
        buffer = io.BytesIO()
        fig.savefig(buffer, format='png', dpi=300, bbox_inches='tight')
        buffer.seek(0)
        img_str = base64.b64encode(buffer.read()).decode('utf-8')
        plt.close(fig)

        return img_str

    def plot_regression_coefficients(self, spillover_results):
        """绘制回归系数图

        Args:
            spillover_results: 溢出效应分析结果

        Returns:
            str: 图像的base64编码
        """
        self.logger.info("绘制回归系数图...")

        # 提取模型结果
        models_data = [
            ('基础模型', spillover_results['results']['basic_model']),
            ('上游关联模型', spillover_results['results']['upstream_model']),
            ('下游关联模型', spillover_results['results']['downstream_model']),
            ('二级网络模型', spillover_results['results']['second_level_model'])
        ]

        # 提取关键变量的系数和p值
        variables = [
            'net_risk_exposure',
            'upstream_ratio',
            'risk_upstream',
            'downstream_ratio',
            'risk_downstream',
            'second_level_risk'
        ]

        # 准备绘图数据
        plot_data = []

        for model_name, model_results in models_data:
            params = model_results['params']
            pvalues = model_results['pvalues']

            for var in variables:
                if var in params:
                    significance = ""
                    if pvalues[var] < 0.01:
                        significance = "***"
                    elif pvalues[var] < 0.05:
                        significance = "**"
                    elif pvalues[var] < 0.1:
                        significance = "*"

                    plot_data.append({
                        'Model': model_name,
                        'Variable': var,
                        'Coefficient': params[var],
                        'P-value': pvalues[var],
                        'Significance': significance
                    })

        # 转换为DataFrame
        coef_df = pd.DataFrame(plot_data)

        # 创建系数图
        plt.figure(figsize=(12, 8))

        # 对每个模型创建子图
        g = sns.catplot(
            data=coef_df,
            kind="bar",
            x="Variable",
            y="Coefficient",
            hue="Model",
            palette=[self.colors['risk'], self.colors['protection'],
                     self.colors['network'], self.colors['reputation']],
            alpha=0.8,
            height=6,
            aspect=1.5
        )

        # 添加显著性标记
        for i, row in coef_df.iterrows():
            g.ax.text(
                i,
                row['Coefficient'] + (0.01 if row['Coefficient'] >= 0 else -0.01),
                row['Significance'],
                ha='center',
                va='center' if row['Coefficient'] >= 0 else 'top',
                color='black',
                fontweight='bold'
            )

        # 添加零线
        g.ax.axhline(y=0, color='gray', linestyle='-', alpha=0.3)

        # 设置图表样式
        g.set_axis_labels("变量", "系数值")
        g.ax.set_title("各模型回归系数比较", fontsize=16)

        # 旋转x轴标签
        plt.xticks(rotation=45, ha='right')

        # 调整布局
        plt.tight_layout()

        # 转换为base64编码
        buffer = io.BytesIO()
        plt.savefig(buffer, format='png', dpi=300, bbox_inches='tight')
        buffer.seek(0)
        img_str = base64.b64encode(buffer.read()).decode('utf-8')
        plt.close()

        return img_str

    def create_interactive_dashboard(self, risk_df, spillover_results, mediation_results, network_img_str):
        """创建交互式仪表板

        Args:
            risk_df: 风险数据
            spillover_results: 溢出效应结果
            mediation_results: 中介效应结果
            network_img_str: 网络图的base64编码

        Returns:
            str: HTML代码
        """
        self.logger.info("创建交互式仪表板...")

        # 提取关键发现
        key_spillover = spillover_results['key_findings']
        key_mediation = mediation_results['key_findings']

        # 创建仪表板HTML
        html = f"""
        <!DOCTYPE html>
        <html>
        <head>
            <title>数字技术风险传导分析仪表板</title>
            <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
            <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
            <style>
                body {{
                    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
                    margin: 0;
                    padding: 0;
                    background-color: {self.colors['background']};
                    color: {self.colors['text']};
                }}
                .dashboard {{
                    max-width: 1200px;
                    margin: 0 auto;
                    padding: 20px;
                }}
                .header {{
                    text-align: center;
                    margin-bottom: 30px;
                    padding: 20px;
                    background: linear-gradient(135deg, #2196F3, #1976D2);
                    color: white;
                    border-radius: 10px;
                    box-shadow: 0 4px 6px rgba(0,0,0,0.1);
                }}
                .card {{
                    background-color: white;
                    border-radius: 10px;
                    box-shadow: 0 4px 6px rgba(0,0,0,0.1);
                    padding: 20px;
                    margin-bottom: 20px;
                }}
                .card-title {{
                    font-size: 1.2rem;
                    font-weight: bold;
                    margin-bottom: 15px;
                    padding-bottom: 10px;
                    border-bottom: 1px solid #e0e0e0;
                }}
                .flex-container {{
                    display: flex;
                    flex-wrap: wrap;
                    gap: 20px;
                    justify-content: space-between;
                }}
                .stat-card {{
                    flex: 1 1 200px;
                    padding: 15px;
                    border-radius: 8px;
                    box-shadow: 0 2px 4px rgba(0,0,0,0.05);
                    text-align: center;
                }}
                .risk {{
                    background-color: rgba(255, 82, 82, 0.1);
                    border-left: 4px solid {self.colors['risk']};
                }}
                .protection {{
                    background-color: rgba(76, 175, 80, 0.1);
                    border-left: 4px solid {self.colors['protection']};
                }}
                .network {{
                    background-color: rgba(33, 150, 243, 0.1);
                    border-left: 4px solid {self.colors['network']};
                }}
                .reputation {{
                    background-color: rgba(255, 193, 7, 0.1);
                    border-left: 4px solid {self.colors['reputation']};
                }}
                .stat-value {{
                    font-size: 1.8rem;
                    font-weight: bold;
                    margin: 10px 0;
                }}
                .network-img {{
                    width: 100%;
                    max-width: 100%;
                    height: auto;
                    border-radius: 8px;
                }}
                .footer {{
                    text-align: center;
                    margin-top: 20px;
                    padding: 20px;
                    font-size: 0.9rem;
                    color: #757575;
                }}
            </style>
        </head>
        <body>
            <div class="dashboard">
                <div class="header">
                    <h1>数字技术风险传导分析仪表板</h1>
                    <p>基于供应链网络和声誉折价机制的综合分析</p>
                </div>

                <!-- 关键指标卡片 -->
                <div class="card">
                    <div class="card-title">关键风险指标</div>
                    <div class="flex-container">
                        <div class="stat-card risk">
                            <h3>平均风险得分</h3>
                            <div class="stat-value">{risk_df['risk_score'].mean():.2f}</div>
                            <p>行业平均风险评分</p>
                        </div>
                        <div class="stat-card protection">
                            <h3>平均防护得分</h3>
                            <div class="stat-value">{risk_df['protection_score'].mean():.2f}</div>
                            <p>行业平均防护能力评分</p>
                        </div>
                        <div class="stat-card network">
                            <h3>平均净风险暴露</h3>
                            <div class="stat-value">{risk_df['net_risk_exposure'].mean():.2f}</div>
                            <p>风险减去防护后的净暴露</p>
                        </div>
                        <div class="stat-card reputation">
                            <h3>中介效应占比</h3>
                            <div class="stat-value">{key_mediation['mediation_proportion'] * 100:.1f}%</div>
                            <p>通过声誉传导的效应比例</p>
                        </div>
                    </div>
                </div>

                <!-- 供应链网络图 -->
                <div class="card">
                    <div class="card-title">供应链风险传导网络</div>
                    <img src="data:image/png;base64,{network_img_str}" class="network-img" alt="供应链网络图">
                </div>

                <!-- 溢出效应分析 -->
                <div class="card">
                    <div class="card-title">供应链溢出效应分析</div>
                    <div class="flex-container">
                        <div style="flex: 1 1 300px;">
                            <h3>关键发现</h3>
                            <ul>
                                <li>风险对企业价值的影响: <b>{key_spillover['risk_impact']:.3f}</b> (p={key_spillover['risk_pvalue']:.3f})</li>
                                <li>上游关联度的影响: <b>{key_spillover['upstream_effect']:.3f}</b> (p={key_spillover['upstream_pvalue']:.3f})</li>
                                <li>下游关联度的影响: <b>{key_spillover['downstream_effect']:.3f}</b> (p={key_spillover['downstream_pvalue']:.3f})</li>
                                <li>二级网络效应: <b>{key_spillover['second_level_effect']:.3f}</b> (p={key_spillover['second_level_pvalue']:.3f})</li>
                            </ul>
                            <p><b>解读:</b> {'上游供应商关联度的影响更显著' if abs(key_spillover['upstream_effect']) > abs(key_spillover['downstream_effect']) else '下游客户关联度的影响更显著'}，这表明{'供应链上游的风险传导更为重要' if abs(key_spillover['upstream_effect']) > abs(key_spillover['downstream_effect']) else '供应链下游的风险传导更为重要'}。</p>
                        </div>
                        <div style="flex: 1 1 300px;">
                            <canvas id="spilloverChart"></canvas>
                        </div>
                    </div>
                </div>

                <!-- 中介效应分析 -->
                <div class="card">
                    <div class="card-title">声誉折价中介效应分析</div>
                    <div class="flex-container">
                        <div style="flex: 1 1 300px;">
                            <h3>中介路径分解</h3>
                            <ul>
                                <li>直接效应: <b>{key_mediation['direct_effect']:.3f}</b></li>
                                <li>通过债务成本: <b>{key_mediation['indirect_effect_debt']:.3f}</b> (Sobel p={key_mediation['sobel_pvalue_debt']:.3f})</li>
                                <li>通过利润波动性: <b>{key_mediation['indirect_effect_vol']:.3f}</b> (Sobel p={key_mediation['sobel_pvalue_vol']:.3f})</li>
                                <li>总间接效应: <b>{key_mediation['total_indirect_effect']:.3f}</b></li>
                                <li>总效应: <b>{key_mediation['total_effect']:.3f}</b></li>
                            </ul>
                            <p><b>解读:</b> {'债务成本是主要的中介路径' if abs(key_mediation['indirect_effect_debt']) > abs(key_mediation['indirect_effect_vol']) else '利润波动性是主要的中介路径'}，占总中介效应的{abs(key_mediation['indirect_effect_debt']) / abs(key_mediation['total_indirect_effect']) * 100 if abs(key_mediation['total_indirect_effect']) > 0 else 0:.1f}%。</p>
                        </div>
                        <div style="flex: 1 1 300px;">
                            <canvas id="mediationChart"></canvas>
                        </div>
                    </div>
                </div>

                <div class="footer">
                    <p>© 2023 数字技术风险研究项目 | 数据更新日期: {pd.Timestamp.now().strftime('%Y-%m-%d')}</p>
                </div>
            </div>

            <script>
                // 溢出效应图表
                                // 溢出效应图表
                const spilloverCtx = document.getElementById('spilloverChart').getContext('2d');
                const spilloverChart = new Chart(spilloverCtx, {
                    type: 'bar',
                    data: {
                        labels: ['自身风险', '上游关联', '下游关联', '二级网络'],
                        datasets: [{
                            label: '对企业价值的影响系数',
                            data: [
                                {key_spillover['risk_impact']}, 
                                {key_spillover['upstream_effect']}, 
                                {key_spillover['downstream_effect']}, 
                                {key_spillover['second_level_effect']}
                            ],
                            backgroundColor: [
                                '{self.colors['risk']}',
                                '{self.colors['protection']}',
                                '{self.colors['network']}',
                                '{self.colors['reputation']}'
                            ],
                            borderColor: [
                                '{self.colors['risk']}',
                                '{self.colors['protection']}',
                                '{self.colors['network']}',
                                '{self.colors['reputation']}'
                            ],
                            borderWidth: 1,
                            barPercentage: 0.6
                        }]
                    },
                    options: {
                        responsive: true,
                        plugins: {{
                            title: {{
                                display: true,
                                text: '风险传导效应分析'
                            }},
                            tooltip: {{
                                callbacks: {{
                                    label: function(context) {{
                                        return `影响系数: ${context.raw.toFixed(3)}`;
                                    }}
                                }}
                            }}
                        }},
                        scales: {{
                            y: {{
                                beginAtZero: true,
                                grid: {{
                                    color: 'rgba(200, 200, 200, 0.2)'
                                }},
                                ticks: {{
                                    callback: function(value) {{
                                        return value.toFixed(2);
                                    }}
                                }}
                            }},
                            x: {{
                                grid: {{
                                    display: false
                                }}
                            }}
                        }}
                    }
                });

                // 中介效应图表
                const mediationCtx = document.getElementById('mediationChart').getContext('2d');
                const mediationChart = new Chart(mediationCtx, {{
                    type: 'doughnut',
                    data: {{
                        labels: ['直接效应', '通过债务成本', '通过利润波动性'],
                        datasets: [{{
                            label: '效应分解',
                            data: [
                                Math.abs({key_mediation['direct_effect']}),
                                Math.abs({key_mediation['indirect_effect_debt']}),
                                Math.abs({key_mediation['indirect_effect_vol']})
                            ],
                            backgroundColor: [
                                '{self.colors['risk']}',
                                '{self.colors['protection']}',
                                '{self.colors['network']}'
                            ],
                            borderColor: [
                                'white',
                                'white',
                                'white'
                            ],
                            borderWidth: 2,
                            hoverOffset: 4
                        }}]
                    }},
                    options: {{
                        responsive: true,
                        plugins: {{
                            title: {{
                                display: true,
                                text: '中介效应比例分解'
                            }},
                            tooltip: {{
                                callbacks: {{
                                    label: function(context) {{
                                        const total = context.dataset.data.reduce((a, b) => a + b, 0);
                                        const percentage = Math.round((context.raw / total) * 100);
                                        return `${context.label}: ${percentage}%`;
                                    }}
                                }}
                            }},
                            legend: {{
                                position: 'bottom'
                            }}
                        }}
                    }}
                }});
            </script>
        </body>
        </html>
        """

        return html


